/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package jeuxEnConsole;

import java.util.HashSet;
import java.util.Random;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author julien
 */
public class Noeud extends NoeudAbstrait {

    HashSet<NoeudAbstrait> fils;
    static int malusNoeudGagnantProfondeur = -100;
    static int NbMaxProfondeur1 = 2;
    public static int NbMaxProfondeur2 = 4;

    public Noeud(PlateauCaracteres plateauCaracteres, int numJoueur) throws CloneNotSupportedException {
        super(plateauCaracteres, numJoueur, 0);
        this.fils = new HashSet<NoeudAbstrait>();

        if (profondeur < NbMaxProfondeur1 - 1) {
            construitFils();
        } else {
            construitFeuilles();
        }
    }

    private Noeud(PlateauCaracteres plateauCaracteres, int numJoueur, int profondeur) throws CloneNotSupportedException {
        super(plateauCaracteres, numJoueur, profondeur);
        this.fils = new HashSet<NoeudAbstrait>();
    }

    @Override
    protected int getValeur() {
        if (!fils.isEmpty()) {
            // si la profondeur est impaire => on choisit pour l'ia le coup
            // le plus mauvais pour le joueur (min)
            if (profondeur % 2 == 1) {
                // on prend la valeur minimum des valeurs des fils
                NoeudAbstrait filsMauvaiseValeur = null;
                int valeurLaPlusMauvaise = 0;
                for (NoeudAbstrait n : fils) {
                    if (filsMauvaiseValeur == null) {
                        filsMauvaiseValeur = n;
                        valeurLaPlusMauvaise = n.getValeur();
                    } else {
                        int valeurLaPlusMauvaiseFils = n.getValeur();
                        if (valeurLaPlusMauvaiseFils < valeurLaPlusMauvaise) {
                            filsMauvaiseValeur = n;
                            valeurLaPlusMauvaise = valeurLaPlusMauvaiseFils;
                        }
                    }
                }

                //System.out.println("return la plus mauvaise valeur a profondeur " + profondeur + ": " + valeurLaPlusMauvaise);
                return valeurLaPlusMauvaise;

            }// sinon c'est le tour de l'autre joueur
            else {
                // on prend la valeur maximum des valeurs des fils
                NoeudAbstrait filsMeilleurValeur = null;
                int valeurLaMeilleur = 0;
                for (NoeudAbstrait n : fils) {
                    if (filsMeilleurValeur == null) {
                        filsMeilleurValeur = n;
                        valeurLaMeilleur = n.getValeur();
                    } else {
                        int valeurLaMeilleurFils = n.getValeur();
                        if (valeurLaMeilleurFils > valeurLaMeilleur) {
                            filsMeilleurValeur = n;
                            valeurLaMeilleur = valeurLaMeilleurFils;
                        }
                    }
                }

                //System.out.println("return la meilleur valeur a profondeur " + profondeur + ": " + valeurLaMeilleur);
                return valeurLaMeilleur;
            }
        } else {
            //System.out.println("return son heuristique a profondeur " + profondeur + ": " + (calculeHeuristique() + (profondeur * malusNoeudGagnantProfondeur)));
            return calculeHeuristique() + profondeur * malusNoeudGagnantProfondeur;
        }
    }

    /*
     * Juste pour prendre le coup dans joueurMachine
     */
    public char[][] getMeilleurCoup() {
        // traitement de l'arbre getValue
        NoeudAbstrait meilleurCoup = null;
        Vector<NoeudAbstrait> listemeilleurCoup = new Vector<NoeudAbstrait>();
        int valeurMeilleurCoup = 0;
        for (NoeudAbstrait coup : fils) {
            //if (meilleurCoup == null) {
            if (listemeilleurCoup.isEmpty()) {
                //meilleurCoup = coup;
                listemeilleurCoup.add(coup);
                //valeurMeilleurCoup = meilleurCoup.getValeur();
                valeurMeilleurCoup = coup.getValeur();
            } else {

                int valeurMeilleurCoupFils = coup.getValeur();

                if (valeurMeilleurCoup < valeurMeilleurCoupFils) {
                    listemeilleurCoup.clear();
                    listemeilleurCoup.removeAllElements();
                    listemeilleurCoup.add(coup);

                    //meilleurCoup = coup;
                    valeurMeilleurCoup = valeurMeilleurCoupFils;
                } else if (valeurMeilleurCoup == valeurMeilleurCoupFils) {
                    listemeilleurCoup.add(coup);
                }
            }
        }

        Random r = new Random();
        System.out.println("Random de " + listemeilleurCoup.size() + ": " + (1 + r.nextInt(listemeilleurCoup.size())));
        meilleurCoup = listemeilleurCoup.get(r.nextInt(listemeilleurCoup.size()));

        listemeilleurCoup.clear();
        listemeilleurCoup.removeAllElements();

        System.out.println("Valeur coup: " + meilleurCoup + "->" + meilleurCoup.calculeHeuristique());
        System.out.println(meilleurCoup.getPlateauCaracteres().toString());
        if (meilleurCoup == null) {
            throw new RuntimeException("Pas de meilleur coup trouvé");
        }
        return meilleurCoup.getPlateauCaracteres().getTabCaracteres();
    }

    private void construitFils() {
        try {
            int adversaire = 0;
            if (numJoueur == 1) {
                adversaire = 2;
            } else {
                adversaire = 1;
            }

            int valeurHeuristique = calculeHeuristique();

            for (String coup : plateauCaracteres.getCoupsPossibles(numJoueur)) {
                PlateauCaracteres p = (PlateauCaracteres) plateauCaracteres.clone();
                p.jouerCoup(coup);

                Noeud n = new Noeud(p, adversaire, profondeur + 1);
                if (profondeur % 2 == 1) {
                    int valeurHeuristiqueFils = n.calculeHeuristique();
                    if (valeurHeuristiqueFils <= valeurHeuristique) {
                        valeurHeuristique = valeurHeuristiqueFils;
                        fils.add(n);
                        if (valeurHeuristique >= 100000) {
                            break;
                        }
                        if (profondeur + 1 < NbMaxProfondeur2 - 1) {
                            n.construitFils();
                        } else {// tester si profondeur < nbMaxProfondeur ?
                            n.construitFeuilles();
                        }
                    }
                } else {
                    int valeurHeuristiqueFils = n.calculeHeuristique();
                    if (valeurHeuristiqueFils >= valeurHeuristique) {
                        valeurHeuristique = valeurHeuristiqueFils;
                        fils.add(n);
                        if (valeurHeuristique >= 100000) {
                            break;
                        }
                        if (profondeur + 1 < NbMaxProfondeur2 - 1) {
                            n.construitFils();
                        } else {// tester si profondeur < nbMaxProfondeur ?
                            n.construitFeuilles();
                        }
                    }
                }
            }
        } catch (CloneNotSupportedException ex) {
            System.out.println("Problème de clonage dans construit fils");
            Logger.getLogger(Noeud.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception e) {
            System.out.println("Problème exception dans construit fils");
            Logger.getLogger(Noeud.class.getName()).log(Level.SEVERE, null, e);
        }
    }

    private void construitFeuilles() {
        try {
            int adversaire = 0;
            if (numJoueur == 1) {
                adversaire = 2;
            } else {
                adversaire = 1;
            }

            for (String coup : plateauCaracteres.getCoupsPossibles(numJoueur)) {

                PlateauCaracteres p = (PlateauCaracteres) plateauCaracteres.clone();
                //System.out.println("ajout d'une feuille avec le coup: " + coup + " --> " + numJoueur);
                p.jouerCoup(coup);

                fils.add(new Feuille(p, adversaire, profondeur + 1));
            }
        } catch (CloneNotSupportedException ex) {
            System.out.println("PB AJOUT FEUILLE");
            System.out.println(ex.getMessage());
            Logger.getLogger(Noeud.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception e) {
            System.out.println("PB AJOUT FEUILLE exception lancé");
            System.out.println(e.getMessage());
            Logger.getLogger(Noeud.class.getName()).log(Level.SEVERE, null, e);
        }
    }

    @Override
    public int getNbCoupsCalcules() {
        int nbCoups = 0;
        for (NoeudAbstrait n : fils) {
            nbCoups += n.getNbCoupsCalcules();
        }
        return nbCoups + 1;
    }
}
